"""
配置管理器 - 支持热更新和验证
"""
import json
import asyncio
from typing import Dict, Any, Optional, List, Callable
from datetime import datetime
from pathlib import Path
import structlog
from pydantic import BaseModel, ValidationError

from .config import Settings, get_settings

logger = structlog.get_logger(__name__)


class ConfigChangeEvent(BaseModel):
    """配置变更事件"""
    timestamp: datetime
    config_key: str
    old_value: Any
    new_value: Any
    user_id: Optional[str] = None
    source: str = "api"  # api, file, system


class CameraAIConfig(BaseModel):
    """摄像头AI算法配置"""
    camera_id: str
    enabled_algorithms: List[str]
    processing_fps: int = 3
    priority_level: int = 5
    custom_settings: Dict[str, Any] = {}


class StreamProcessingConfig(BaseModel):
    """流处理配置"""
    enabled: bool = True
    workers: int = 10
    cameras_per_worker: int = 50
    health_check_interval: int = 30
    restart_cooldown: int = 60
    max_latency: float = 2.0
    adaptive_fps: bool = True
    min_fps: int = 1
    max_fps: int = 10


class ConfigManager:
    """配置管理器"""
    
    def __init__(self):
        self.settings = get_settings()
        self._change_listeners: List[Callable] = []
        self._change_history: List[ConfigChangeEvent] = []
        self._camera_ai_configs: Dict[str, CameraAIConfig] = {}
        self._config_backup_path = Path("./data/config_backups")
        self._config_backup_path.mkdir(exist_ok=True)
        
    def add_change_listener(self, callback: Callable[[ConfigChangeEvent], None]):
        """添加配置变更监听器"""
        self._change_listeners.append(callback)
        
    def remove_change_listener(self, callback: Callable):
        """移除配置变更监听器"""
        if callback in self._change_listeners:
            self._change_listeners.remove(callback)
    
    async def _notify_change(self, event: ConfigChangeEvent):
        """通知配置变更"""
        self._change_history.append(event)
        
        # 保留最近1000条变更记录
        if len(self._change_history) > 1000:
            self._change_history = self._change_history[-1000:]
        
        # 通知所有监听器
        for listener in self._change_listeners:
            try:
                if asyncio.iscoroutinefunction(listener):
                    await listener(event)
                else:
                    listener(event)
            except Exception as e:
                logger.error("配置变更通知失败", listener=listener, error=str(e))
    
    def _backup_config(self, config_key: str, old_value: Any):
        """备份配置"""
        if not self.settings.CONFIG_BACKUP_ENABLED:
            return
            
        try:
            backup_file = self._config_backup_path / f"{config_key}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
            backup_data = {
                "timestamp": datetime.now().isoformat(),
                "config_key": config_key,
                "value": old_value
            }
            
            with open(backup_file, 'w', encoding='utf-8') as f:
                json.dump(backup_data, f, ensure_ascii=False, indent=2, default=str)
                
        except Exception as e:
            logger.error("配置备份失败", config_key=config_key, error=str(e))
    
    def _validate_config_value(self, config_key: str, value: Any) -> bool:
        """验证配置值"""
        if not self.settings.CONFIG_VALIDATION_ENABLED:
            return True
            
        try:
            # 基本类型验证
            if config_key == "STREAM_PROCESSING_WORKERS" and isinstance(value, int):
                return 1 <= value <= 50
            elif config_key == "CAMERAS_PER_WORKER" and isinstance(value, int):
                return 1 <= value <= 200
            elif config_key == "VIDEO_PROCESSING_FPS" and isinstance(value, int):
                return 1 <= value <= 30
            elif config_key == "MAX_PROCESSING_LATENCY" and isinstance(value, (int, float)):
                return 0.1 <= value <= 10.0
            elif config_key == "PERFORMANCE_ALERT_THRESHOLD" and isinstance(value, dict):
                required_keys = ["cpu_usage", "memory_usage", "gpu_usage", "processing_latency", "frame_drop_rate"]
                return all(key in value for key in required_keys)
            
            return True
            
        except Exception as e:
            logger.error("配置验证失败", config_key=config_key, value=value, error=str(e))
            return False
    
    async def update_config(self, config_key: str, value: Any, user_id: Optional[str] = None) -> bool:
        """更新配置"""
        try:
            # 获取当前值
            old_value = getattr(self.settings, config_key, None)
            
            # 验证新值
            if not self._validate_config_value(config_key, value):
                logger.warning("配置值验证失败", config_key=config_key, value=value)
                return False
            
            # 备份旧值
            self._backup_config(config_key, old_value)
            
            # 更新配置
            setattr(self.settings, config_key, value)
            
            # 记录变更事件
            event = ConfigChangeEvent(
                timestamp=datetime.now(),
                config_key=config_key,
                old_value=old_value,
                new_value=value,
                user_id=user_id
            )
            
            await self._notify_change(event)
            
            logger.info("配置更新成功", config_key=config_key, old_value=old_value, new_value=value)
            return True
            
        except Exception as e:
            logger.error("配置更新失败", config_key=config_key, value=value, error=str(e))
            return False
    
    async def update_camera_ai_config(self, camera_id: str, config: CameraAIConfig, user_id: Optional[str] = None) -> bool:
        """更新摄像头AI算法配置"""
        try:
            old_config = self._camera_ai_configs.get(camera_id)
            
            # 验证AI算法列表
            available_algorithms = [
                "behavior_analysis", "crowd_density", "waste_detection",
                "cleanliness_assessment", "teaching_quality", "classroom_quality",
                "conflict_detection", "pose_detection", "trajectory_analysis",
                "lighting_detection", "energy_analysis"
            ]
            
            for algorithm in config.enabled_algorithms:
                if algorithm not in available_algorithms:
                    logger.warning("未知的AI算法", algorithm=algorithm)
                    return False
            
            # 验证帧率和优先级
            if not (1 <= config.processing_fps <= 30):
                logger.warning("无效的处理帧率", fps=config.processing_fps)
                return False
                
            if not (1 <= config.priority_level <= 10):
                logger.warning("无效的优先级", priority=config.priority_level)
                return False
            
            # 更新配置
            self._camera_ai_configs[camera_id] = config
            
            # 记录变更事件
            event = ConfigChangeEvent(
                timestamp=datetime.now(),
                config_key=f"camera_ai_config_{camera_id}",
                old_value=old_config.dict() if old_config else None,
                new_value=config.dict(),
                user_id=user_id
            )
            
            await self._notify_change(event)
            
            logger.info("摄像头AI配置更新成功", camera_id=camera_id)
            return True
            
        except Exception as e:
            logger.error("摄像头AI配置更新失败", camera_id=camera_id, error=str(e))
            return False
    
    def get_camera_ai_config(self, camera_id: str) -> Optional[CameraAIConfig]:
        """获取摄像头AI算法配置"""
        return self._camera_ai_configs.get(camera_id)
    
    def get_all_camera_ai_configs(self) -> Dict[str, CameraAIConfig]:
        """获取所有摄像头AI算法配置"""
        return self._camera_ai_configs.copy()
    
    async def batch_update_camera_configs(self, configs: Dict[str, CameraAIConfig], user_id: Optional[str] = None) -> Dict[str, bool]:
        """批量更新摄像头配置"""
        results = {}
        
        for camera_id, config in configs.items():
            results[camera_id] = await self.update_camera_ai_config(camera_id, config, user_id)
        
        return results
    
    def get_stream_processing_config(self) -> StreamProcessingConfig:
        """获取流处理配置"""
        return StreamProcessingConfig(
            enabled=self.settings.REAL_TIME_PROCESSING_ENABLED,
            workers=self.settings.STREAM_PROCESSING_WORKERS,
            cameras_per_worker=self.settings.CAMERAS_PER_WORKER,
            health_check_interval=self.settings.STREAM_HEALTH_CHECK_INTERVAL,
            restart_cooldown=self.settings.STREAM_RESTART_COOLDOWN,
            max_latency=self.settings.MAX_PROCESSING_LATENCY,
            adaptive_fps=self.settings.ADAPTIVE_FPS_ENABLED,
            min_fps=self.settings.MIN_PROCESSING_FPS,
            max_fps=self.settings.MAX_PROCESSING_FPS
        )
    
    async def update_stream_processing_config(self, config: StreamProcessingConfig, user_id: Optional[str] = None) -> bool:
        """更新流处理配置"""
        try:
            old_config = self.get_stream_processing_config()
            
            # 批量更新相关配置
            updates = [
                ("REAL_TIME_PROCESSING_ENABLED", config.enabled),
                ("STREAM_PROCESSING_WORKERS", config.workers),
                ("CAMERAS_PER_WORKER", config.cameras_per_worker),
                ("STREAM_HEALTH_CHECK_INTERVAL", config.health_check_interval),
                ("STREAM_RESTART_COOLDOWN", config.restart_cooldown),
                ("MAX_PROCESSING_LATENCY", config.max_latency),
                ("ADAPTIVE_FPS_ENABLED", config.adaptive_fps),
                ("MIN_PROCESSING_FPS", config.min_fps),
                ("MAX_PROCESSING_FPS", config.max_fps)
            ]
            
            success_count = 0
            for config_key, value in updates:
                if await self.update_config(config_key, value, user_id):
                    success_count += 1
            
            return success_count == len(updates)
            
        except Exception as e:
            logger.error("流处理配置更新失败", error=str(e))
            return False
    
    def get_change_history(self, limit: int = 100) -> List[ConfigChangeEvent]:
        """获取配置变更历史"""
        return self._change_history[-limit:]
    
    def get_config_summary(self) -> Dict[str, Any]:
        """获取配置摘要"""
        return {
            "stream_processing": self.get_stream_processing_config().dict(),
            "camera_ai_configs_count": len(self._camera_ai_configs),
            "performance_monitoring": {
                "enabled": self.settings.PERFORMANCE_MONITORING_ENABLED,
                "metrics_interval": self.settings.METRICS_COLLECTION_INTERVAL,
                "alert_thresholds": self.settings.PERFORMANCE_ALERT_THRESHOLD
            },
            "hot_reload": {
                "enabled": self.settings.CONFIG_HOT_RELOAD_ENABLED,
                "validation_enabled": self.settings.CONFIG_VALIDATION_ENABLED,
                "backup_enabled": self.settings.CONFIG_BACKUP_ENABLED
            }
        }
    
    async def reset_to_defaults(self, config_keys: List[str], user_id: Optional[str] = None) -> Dict[str, bool]:
        """重置配置到默认值"""
        results = {}
        default_settings = Settings()
        
        for config_key in config_keys:
            try:
                default_value = getattr(default_settings, config_key, None)
                if default_value is not None:
                    results[config_key] = await self.update_config(config_key, default_value, user_id)
                else:
                    results[config_key] = False
                    logger.warning("未找到默认配置", config_key=config_key)
            except Exception as e:
                results[config_key] = False
                logger.error("重置配置失败", config_key=config_key, error=str(e))
        
        return results


# 全局配置管理器实例
config_manager = ConfigManager()


def get_config_manager() -> ConfigManager:
    """获取配置管理器实例"""
    return config_manager